/*
  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.

  Copyright (c) 2006-2009 PRO ACTIVE SAS - www.proactive-group.com
   
  Ref_AskCts256b.c
  ----------------

  This is the reference applications that shows how to read/write data
  in a ASK CTS256B tag.
  
  JDA 11/15/2006 : initial release
  JDA 10/01/2007 : fixed a few warnings when compiling under GCC
  JDA 12/04/2007 : minor changes to mimic CTS512 sample

*/
#include "products/springprox/springprox.h"

#include <stdio.h>
#include <string.h>

SWORD SPROX_ConfigureForCTS(void);

SWORD SPROX_CTS256_Request(BYTE req_data[2]);
SWORD SPROX_CTS256_Deactivate(void);
SWORD SPROX_CTS256_Read(BYTE addr, BYTE value[2]);
SWORD SPROX_CTS256_Write(BYTE addr, const BYTE value[2]);
SWORD SPROX_CTS256_Erase(BYTE addr);

int main(int argc, char **argv)
{
  SWORD rc;
  char s_buffer[64];
  BYTE code[2];
  BYTE data[32];
  BYTE addr;

  char *device = NULL;

  if (argc > 1)
    device = argv[1];

  printf("SpringCard SDK for K531/SpringProx-CF/CSB Legacy\n");
  printf("\n");
  printf("ASK CTS 256B reference demo\n");
  printf("---------------------------\n");
  printf("www.springcard.com\n\n");

  rc = SPROX_GetLibrary(s_buffer, sizeof(s_buffer));
  if (rc != MI_OK)
  {
    printf("Failed to get API version\n");
    goto done;
  }
  printf("API version : %s\n", s_buffer);
  printf("\n");

  /* Open reader */
  /* ----------- */

  rc = SPROX_ReaderOpen(device);
  if (rc != MI_OK)
  {
    printf("Reader not found\n");
    goto done;
  }

  rc = SPROX_ReaderGetDevice(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader found on %s\n", s_buffer);

  rc = SPROX_ReaderGetFirmware(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader firwmare is %s\n", s_buffer);

  /* Configure reader for ASK memory cards operation */
  /* ----------------------------------------------- */
  rc = SPROX_ConfigureForCTS();
  if (rc != MI_OK)
  {
    printf("Failed to configure the reader\n");
    return 0;
  }

  /* RF field ON */
  SPROX_ControlRF(TRUE);

  printf("Put your ASK CTS 256B card on the reader...\n");

  /* Select a compliant tag */
  /* ---------------------- */
  for (;;)
  {
    rc = SPROX_CTS256_Request(code);
    if (rc == MI_OK)
      break;
  }

  printf("Tag found, product code = %02X, fab code = %02X\n", code[0], code[1]);
  if ((code[1] & 0xF0) != 0x50)
    printf("Hum, seams that this is NOT a CTS256B. Trying to read anyway...\n");
  printf("Reading 16 blocks...\n");

  for (addr = 0; addr < 16; addr++)
  {
    rc = SPROX_CTS256_Read(addr, &data[2 * addr]);
    if (rc == MI_OK)
    {
      printf("Block %02d : %02X%02X\n", addr, data[2 * addr],
             data[2 * addr + 1]);
    } else
    {
      printf("Block %02d : Read failed, error %d\n", addr, rc);
    }
  }

  printf("Updating blocks 5 to 15...\n");
  for (addr = 5; addr < 16; addr++)
  {
    rc = SPROX_CTS256_Erase(addr);
    if (rc != MI_OK)
    {
      printf("Block %02d : Erase failed, error %d\n", addr, rc);
    }
    data[2 * addr] = 0xA0 | addr;
    data[2 * addr + 1] = 0xB0 | addr;
    rc = SPROX_CTS256_Write(addr, &data[2 * addr]);
    if (rc != MI_OK)
    {
      printf("Block %02d : Write failed, error %d\n", addr, rc);
    }
  }

  printf("Reading blocks 5 to 15 again, and erasing...\n");
  for (addr = 5; addr < 16; addr++)
  {
    rc = SPROX_CTS256_Read(addr, &data[2 * addr]);
    if (rc == MI_OK)
    {
      printf("Block %02d : %02X%02X\n", addr, data[2 * addr],
             data[2 * addr + 1]);
    } else
    {
      printf("Block %02d : Read failed, error %d\n", addr, rc);
    }
    rc = SPROX_CTS256_Erase(addr);
    if (rc != MI_OK)
    {
      printf("Block %02d : Erase failed, error %d\n", addr, rc);
    }
  }

  printf("Reading blocks 5 to 15 again...\n");
  for (addr = 5; addr < 16; addr++)
  {
    rc = SPROX_CTS256_Read(addr, &data[2 * addr]);
    if (rc == MI_OK)
    {
      printf("Block %02d : %02X%02X\n", addr, data[2 * addr],
             data[2 * addr + 1]);
    } else
    {
      printf("Block %02d : Read failed, error %d\n", addr, rc);
    }
  }

  rc = SPROX_CTS256_Deactivate();
  if (rc != MI_OK)
  {
    printf("Deactivation error %d\n", rc);
  }

  /* Close the reader */
  SPROX_ControlRF(FALSE);
  SPROX_ReaderClose();

done:
  /* Display last error */
  if (rc == MI_OK)
  {
    printf("Done\n");
  } else
  {
    printf("%s (%d)\n", SPROX_GetErrorMessage(rc), rc);
  }
  return 0;
}

/*
 * Configure the reader for ASK CTS operation
 * ------------------------------------------
 */
SWORD SPROX_ConfigureForCTS(void)
{
  SWORD rc;

  /* Enter ISO 14443-B mode */
  rc = SPROX_SetConfig(CFG_MODE_ISO_14443_B);
  if (rc != MI_OK)
    return rc;

  rc = WriteRIC(0x17, 0x00);
  if (rc != MI_OK)
    return rc;

  rc = WriteRIC(0x1D, 0xFE);
  if (rc != MI_OK)
    return rc;

  return MI_OK;
}

SWORD SPROX_CTS256_Request(BYTE req_data[2])
{
  /* REQT is only a READ at address 0 */
  return SPROX_CTS256_Read(0, req_data);
}

SWORD SPROX_CTS256_Deactivate(void)
{
  BYTE buffer[3];
  WORD len = 3;
  SWORD rc;

  /* DEACTIVATE command */
  buffer[0] = 0x80;

  /* Timeout = 1ms, but no answer expected */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 106);
  if (rc == MI_NOTAGERR)
    rc = MI_OK;

  return rc;
}

SWORD SPROX_CTS256_Read(BYTE addr, BYTE value[2])
{
  BYTE buffer[4];
  WORD len = 4;
  SWORD rc;

  /* READ command */
  buffer[0] = 0x10 | (addr & 0x0F);

  /* Timeout = 1ms */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 106);
  if (rc != MI_OK)
    return rc;

  /* 2 bytes (+CRC) expected */
  if (len != 4)
    return MI_WRONG_LENGTH;

  if (value != NULL)
    memcpy(value, buffer, 2);

  return MI_OK;
}

SWORD SPROX_CTS256_Write(BYTE addr, const BYTE value[2])
{
  BYTE buffer[5];
  WORD len = 3;
  SWORD rc;

  /* We need something to write... */
  if (value == NULL)
    return MI_LIB_CALL_ERROR;

  /* Before writing we must read the system bits */
  rc = SPROX_CTS256_Read(1, NULL);
  if (rc != MI_OK)
    return rc;

  /* WRITE command with 2 bytes of data */
  buffer[0] = 0x20 | (addr & 0x0F);
  memcpy(&buffer[1], value, 2);

  /* Timeout = 2ms, but no answer expected */
  rc = SPROX_B_Exchange(buffer, 5, buffer, &len, TRUE, 212);
  if (rc == MI_NOTAGERR)
    rc = MI_OK;

  return rc;
}

SWORD SPROX_CTS256_Erase(BYTE addr)
{
  BYTE buffer[3];
  WORD len = 3;
  SWORD rc;

  /* Before erasing we must read the system bits */
  rc = SPROX_CTS256_Read(1, NULL);
  if (rc != MI_OK)
    return rc;

  /* ERASE command */
  buffer[0] = 0x40 | (addr & 0x0F);

  /* Timeout = 2ms, but no answer expected */
  rc = SPROX_B_Exchange(buffer, 3, buffer, &len, TRUE, 212);
  if (rc == MI_NOTAGERR)
    rc = MI_OK;

  return rc;
}
